﻿using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Taxonomy;
using System.Linq;
using System.Collections.Generic;

namespace P3.Modules.SharePoint.AutoTag.AutoTagER
{
    class DisabledEventsScope : SPItemEventReceiver, IDisposable
    {
        // Boolean to hold the original value of the EventFiringEnabled property 
        bool _originalValue;

        public DisabledEventsScope()
        {
            // Save off the original value of EventFiringEnabled 
            _originalValue = base.EventFiringEnabled;

            // Set EventFiringEnabled to false to disable it 
            base.EventFiringEnabled = false;
        }

        public void Dispose()
        {
            // Set EventFiringEnabled back to its original value 
            base.EventFiringEnabled = _originalValue;
        }
        
    }


    /// <summary>
    /// List Item Events
    /// </summary>
    public class AutoTagER : SPItemEventReceiver
    {
       /// <summary>
       /// An item was updated.
       /// </summary>
       public override void ItemUpdated(SPItemEventProperties properties)
       {
           setmetadatafield(properties);
           base.ItemUpdated(properties);
       }
       
       public void setmetadatafield(SPItemEventProperties properties)
       {
           SPList list = properties.List;
           string propertyValue = getPropertyValue(list.ID.ToString(), properties.Web);
           string[] fieldNames = null;
           string[] term = null;
           int endtag;
           if (propertyValue != "")
           {
               if (propertyValue.Contains("$") == true)
               {
                   string[] seperator = { "$" };
                   fieldNames = propertyValue.Split(seperator, StringSplitOptions.None);
                   if (fieldNames.Length == 2)
                   {
                       string srcValue = (properties.List.Fields[fieldNames[0]] as SPFieldMultiLineText).GetFieldValueAsText(properties.ListItem[fieldNames[0]] as string);
                       if ((!string.IsNullOrEmpty(srcValue)) && (srcValue.Contains("#") == true))
                       {
                           srcValue = srcValue.Replace(Environment.NewLine, " ").Replace("\r", " ");
                           List<int> positions = AllIndexesOf(srcValue, "#");
                           int j = 0;
                           term = new string[positions.Count];
                           foreach (int i in positions)
                           {
                               endtag = srcValue.IndexOf(" ", i);
                               if (endtag == -1)
                                   term[j] = srcValue.Substring(i + 1);
                               else
                                   term[j] = srcValue.Substring(i + 1, (endtag - i));
                               term[j] = term[j].Replace('_', ' ');
                               j++;
                           }
                           if (term.Length > 0)
                           {
                               setMeatadataCol(properties.OpenSite(), properties.ListItem, list, fieldNames[1], term);
                           }

                       }
                   }
               }

           }
       }

        /// <summary>
        /// Gets positions of all occurences of spcified value
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <returns></returns>
       public List<int> AllIndexesOf(string str, string value)
       {
           List<int> indexes = new List<int>();
           for (int index = 0; ; index += value.Length)
           {
               index = str.IndexOf(value, index);
               if (index == -1)
                   return indexes;
               indexes.Add(index);
           }

       }

        /// <summary>
        /// Get web property value based on the list name
        /// </summary>
        /// <param name="listName"></param>
        /// <param name="web"></param>
        /// <returns></returns>
       public string getPropertyValue(string listID, SPWeb web)
       {
           string propertyName = "TagConfig_" + listID;
           string propertyValue = "";
           if (!string.IsNullOrEmpty(web.AllProperties[propertyName] as string))
           {
               propertyValue = web.GetProperty(propertyName) as string;
           }
           return (propertyValue);
       }

        /// <summary>
        /// Create term if term is not in termset and updates the list item field by appending new term 
        /// </summary>
        /// <param name="site"></param>
        /// <param name="item"></param>
        /// <param name="list"></param>
        /// <param name="metadataFieldName"></param>
        /// <param name="termnames"></param>
       private void setMeatadataCol(SPSite site, SPListItem item, SPList list, string metadataFieldName, string[] termnames)
       {
           var managedMetaDataField = list.Fields[metadataFieldName] as TaxonomyField;

           var termsetId = managedMetaDataField.TermSetId;

           var termstoreId = managedMetaDataField.SspId;

           var taxonomySession = new TaxonomySession(site);

           var termstore = taxonomySession.TermStores[termstoreId];

           var termset = termstore.GetTermSet(termsetId);

           //get current terms from the field
           TaxonomyFieldValueCollection FieldValueColl = (item[metadataFieldName] as TaxonomyFieldValueCollection);

           Term oterm = null;

           bool updateField = false;

           foreach (string termname in termnames)
           {
               TaxonomyFieldValue fieldValue = new TaxonomyFieldValue(managedMetaDataField);
               var terms = termset.GetTerms(termname, false);

               Term term1;

               if (terms.Count == 0)
               {
                   term1 = termset.CreateTerm(termname, 1033);
                   termstore.CommitAll();
               }
               else
               {
                   term1 = terms[0];
               }
               if (managedMetaDataField.AllowMultipleValues == false)
               {
                   oterm = term1;
                   updateField = true;
                   break;
               }
               else
               {
                   fieldValue.TermGuid = term1.Id.ToString();
                   fieldValue.Label = term1.Name;
                   if ((FieldValueColl.Any(x => x.TermGuid == fieldValue.TermGuid)) == false)
                   {
                       FieldValueColl.Add(fieldValue);
                       updateField = true;
                   }
               }

           }
           if (updateField == true)
           {
               using (DisabledEventsScope scope = new DisabledEventsScope())
               {
                   if (managedMetaDataField.AllowMultipleValues == true)
                       managedMetaDataField.SetFieldValue(item, FieldValueColl);
                   else
                       managedMetaDataField.SetFieldValue(item, oterm);
                   item.SystemUpdate();
               }
           }

       }

    }
}
